#pragma once
#include "formatter.hpp"
#include "sink.hpp"
#include "message.hpp"
#include "asynclooper.hpp"
#include <mutex>
#include <atomic>
#include <stdarg.h>
#include <unordered_map>

namespace ns_log
{
    class Logger
    {
    public:
        using ptr = std::shared_ptr<Logger>;
        Logger(const std::string &logger_name, LogLevel::value limit_level, const Formatter::ptr &formatter,
               const std::vector<FSLogSink::ptr> &fs_sinks, const std::vector<DBLogSink::ptr> &db_sinks)
            : _logger_name(logger_name), _limit_level(limit_level), _formatter(formatter), _fs_sinks(fs_sinks), _db_sinks(db_sinks) {}

        virtual ~Logger() {}

        const std::string &name() { return _logger_name; }

        void debug(const std::string &file, size_t line, const std::string &body_format, ...)
        {
            // 1. 比较日志等级
            if (_limit_level > LogLevel::value::DEBUG)
                return;
            // 2. 解析参数
            va_list ap;
            va_start(ap, body_format);
            char *body = nullptr;
            if (-1 == vasprintf(&body, body_format.c_str(), ap))
            {
                std::cout << "debug: vasprintf失败\n";
                return;
            }
            va_end(ap);
            // 3. 复用
            construct(LogLevel::value::DEBUG, file, line, body);
        }

        void info(const std::string &file, size_t line, const std::string &body_format, ...)
        {
            // 1. 比较日志等级
            if (_limit_level > LogLevel::value::INFO)
                return;
            // 2. 解析参数
            va_list ap;
            va_start(ap, body_format);
            char *body = nullptr;
            if (-1 == vasprintf(&body, body_format.c_str(), ap))
            {
                std::cout << "info: vasprintf失败\n";
                return;
            }
            va_end(ap);
            // 3. 复用
            construct(LogLevel::value::INFO, file, line, body);
        }

        void warning(const std::string &file, size_t line, const std::string &body_format, ...)
        {
            // 1. 比较日志等级
            if (_limit_level > LogLevel::value::WARNING)
                return;
            // 2. 解析参数
            va_list ap;
            va_start(ap, body_format);
            char *body = nullptr;
            if (-1 == vasprintf(&body, body_format.c_str(), ap))
            {
                std::cout << "warning: vasprintf失败\n";
                return;
            }
            va_end(ap);
            // 3. 复用
            construct(LogLevel::value::WARNING, file, line, body);
        }

        void error(const std::string &file, size_t line, const std::string &body_format, ...)
        {
            // 1. 比较日志等级
            if (_limit_level > LogLevel::value::ERROR)
                return;
            // 2. 解析参数
            va_list ap;
            va_start(ap, body_format);
            char *body = nullptr;
            if (-1 == vasprintf(&body, body_format.c_str(), ap))
            {
                std::cout << "error: vasprintf失败\n";
                return;
            }
            va_end(ap);
            // 3. 复用
            construct(LogLevel::value::ERROR, file, line, body);
        }

        void fatal(const std::string &file, size_t line, const std::string &body_format, ...)
        {
            // 1. 比较日志等级
            if (_limit_level > LogLevel::value::FATAL)
                return;
            // 2. 解析参数
            va_list ap;
            va_start(ap, body_format);
            char *body = nullptr;
            if (-1 == vasprintf(&body, body_format.c_str(), ap))
            {
                std::cout << "fatal: vasprintf失败\n";
                return;
            }
            va_end(ap);
            // 3. 复用
            construct(LogLevel::value::FATAL, file, line, body);
        }

        // 因为下面的成员需要能够被子类所访问到, 因此我们不搞成private, 而是搞成protected
    protected:
        void construct(LogLevel::value level, const std::string &file, size_t line, char *body)
        {
            // 1. 构造LogMessage
            LogMessage message(level, file, line, _logger_name, body);
            // 2. free掉body,否则会内存泄漏
            free(body);
            body = nullptr;
            // 3. 将LogMessage进行格式化
            std::string real_message = _formatter->format(message);
            // 4. 复用log进行实际的日志落地
            log_fs(real_message.c_str(), real_message.size());
            log_db(message);
        }

        virtual void log_fs(const char *data, size_t len) = 0;

        virtual void log_db(const LogMessage &message) = 0;

        std::string _logger_name;
        std::mutex _mutex;
        std::atomic<LogLevel::value> _limit_level;
        std::vector<FSLogSink::ptr> _fs_sinks;
        std::vector<DBLogSink::ptr> _db_sinks;
        Formatter::ptr _formatter;
    };

    class SyncLogger : public Logger
    {
    public:
        SyncLogger(const std::string &logger_name, LogLevel::value limit_level, const Formatter::ptr &formatter,
                   const std::vector<FSLogSink::ptr> &fs_sinks, const std::vector<DBLogSink::ptr> &db_sinks)
            : Logger(logger_name, limit_level, formatter, fs_sinks, db_sinks) {}

        virtual void log_fs(const char *data, size_t len)
        {
            // 这里必须要加锁，因为存在多线程同时调用同一个日志器对象的log函数的情况
            std::unique_lock<std::mutex> ulock(_mutex);
            for (auto &sp : _fs_sinks)
            {
                sp->log(data, len);
            }
        }

        virtual void log_db(const LogMessage &message)
        {
            // 这里必须要加锁，因为存在多线程同时调用同一个日志器对象的log函数的情况
            std::unique_lock<std::mutex> ulock(_mutex);
            for (auto &sp : _db_sinks)
            {
                sp->log(message);
            }
        }
    };

    class AsyncLogger : public Logger
    {
    public:
        AsyncLogger(const std::string &logger_name, LogLevel::value limit_level, const Formatter::ptr &formatter,
                    const std::vector<FSLogSink::ptr> &fs_sinks, const std::vector<DBLogSink::ptr> &db_sinks, AsyncType type = AsyncType::ASYNC_SAFE)
            : Logger(logger_name, limit_level, formatter, fs_sinks, db_sinks),
              _looper(std::make_shared<AsyncLooper>(std::bind(&AsyncLogger::realFSLog, this, std::placeholders::_1),
                                                    std::bind(&AsyncLogger::realDBLog, this, std::placeholders::_1), type))
        {
        }

        // 在业务线程看来，调用log函数之后，就意味着日志打印完毕
        // 对于异步日志器来说，业务线程只需要将日志写入日志缓冲区即可
        // 因此这里的log只需要将日志写入日志缓冲区即可
        virtual void log_fs(const char *data, size_t len)
        {
            _looper->push_fs(data, len);
        }

        virtual void log_db(const LogMessage &message)
        {
            _looper->push_db(message);
        }

        void realFSLog(FSBuffer &buffer)
        {
            // 无需加锁，因为_looper内部本来就加锁了
            const char *begin = buffer.begin();
            size_t len = buffer.readableSize();
            for (auto &elem : _fs_sinks)
            {
                elem->log(begin, len);
            }
            buffer.moveReader(len);
        }

        void realDBLog(DBBuffer &buffer)
        {
            // 无需加锁, 因为_looper内部本来就加锁了
            // for (int i = 0; i < buffer.readableSize(); i++)
            // {
            //     for (auto &sink : _db_sinks)
            //     {
            //         sink->log(buffer[i]);
            //     }
            // }
            size_t readableSize = buffer.readableSize();
            for (auto &sink : _db_sinks)
            {
                sink->log(buffer.getBuffer(), readableSize);
            }
        }

    private:
        AsyncLooper::ptr _looper;
    };

    enum class LoggerType
    {
        SYNC,
        ASYNC
    };

    class LoggerBuilder
    {
    public:
        using ptr = std::shared_ptr<LoggerBuilder>;

        LoggerBuilder() : _logger_type(LoggerType::SYNC), _limit_level(LogLevel::value::DEBUG) {}
        virtual ~LoggerBuilder() {}

        void buildLoggerName(const std::string &logger_name)
        {
            _logger_name = logger_name;
        }

        void buildLoggerType(LoggerType logger_type)
        {
            _logger_type = logger_type;
        }

        void buildLimitLevel(LogLevel::value limit_level)
        {
            _limit_level = limit_level;
        }

        void buildFormatter(const std::string &pattern = "")
        {
            if (pattern.empty())
                _formatter = std::make_shared<Formatter>();
            else
                _formatter = std::make_shared<Formatter>(pattern);
        }

        template <class SinkType, class... Args>
        void buildFSLogSink(Args &&...args)
        {
            _fs_sinks.push_back(LogSinkFactory::create_fs<SinkType>(std::forward<Args>(args)...));
        }

        template <class SinkType, class... Args>
        void buildDBLogSink(Args &&...args)
        {
            _db_sinks.push_back(LogSinkFactory::create_db<SinkType>(std::forward<Args>(args)...));
        }

        void buildAsyncType(AsyncType async_type)
        {
            _async_type = async_type;
        }

        virtual Logger::ptr build() = 0;

    protected:
        // 允许一个建造者在调用build接口构造完对象之后将建造者当中保存的原数据进行重置
        void reset()
        {
            _logger_name.clear();
            _logger_type = LoggerType::SYNC;
            _limit_level = LogLevel::value::DEBUG;
            _fs_sinks.clear();
            _db_sinks.clear();
            _formatter.reset();
        }

        std::string _logger_name;
        LoggerType _logger_type;
        AsyncType _async_type;
        LogLevel::value _limit_level;
        std::vector<FSLogSink::ptr> _fs_sinks;
        std::vector<DBLogSink::ptr> _db_sinks;
        Formatter::ptr _formatter;
    };

    class LocalLoggerBuilder : public LoggerBuilder
    {
    public:
        virtual Logger::ptr build()
        {
            if (_logger_name.empty())
            {
                std::cout << "日志器名称为空！！\n";
                abort();
            }
            if (_formatter.get() == nullptr)
            {
                _formatter = std::make_shared<Formatter>();
            }
            if (_fs_sinks.empty() && _db_sinks.empty())
            {
                _fs_sinks.push_back(LogSinkFactory::create_fs<StdoutSink>());
            }
            Logger::ptr ret;
            if (_logger_type == LoggerType::SYNC)
            {
                ret = std::make_shared<SyncLogger>(_logger_name, _limit_level, _formatter, _fs_sinks, _db_sinks);
            }
            else
            {
                // 后面实现完异步日志器之后完善
                ret = std::make_shared<AsyncLogger>(_logger_name, _limit_level, _formatter, _fs_sinks, _db_sinks, _async_type);
            }
            // 重置
            this->reset();
            return ret;
        }
    };

    const std::string default_logger_name = "_default_logger";

    class LoggerManager
    {
    public:
        static LoggerManager &getInstance()
        {
            static LoggerManager logger_manager;
            return logger_manager;
        }

        // 增删查
        void addLogger(const Logger::ptr &logger)
        {
            std::unique_lock<std::mutex> ulock(_mutex);
            _logger_map.insert(std::make_pair(logger->name(), logger));
        }

        void delLogger(const std::string &logger_name)
        {
            std::unique_lock<std::mutex> ulock(_mutex);
            _logger_map.erase(logger_name);
        }

        Logger::ptr getLogger(const std::string &logger_name)
        {
            std::unique_lock<std::mutex> ulock(_mutex);
            auto iter = _logger_map.find(logger_name);
            if (iter == _logger_map.end())
                return Logger::ptr();
            else
                return iter->second;
        }

        bool existLogger(const std::string &logger_name)
        {
            std::unique_lock<std::mutex> ulock(_mutex);
            return _logger_map.count(logger_name) > 0;
        }

        Logger::ptr default_logger()
        {
            // 无需加锁,因为没人修改它
            return _default_logger;
        }

    private:
        // 构造和析构私有
        LoggerManager()
        {
            // 创建默认日志器
            // 这里必须是局部日志器, 如果是全局日志器的话, 调用其build创建对象之后, 其会将该日志器添加到单例对象当中
            // 而此时单例对象还没有创建好, 此时就发生相互依赖问题导致的死循环
            LoggerBuilder::ptr builder = std::make_shared<LocalLoggerBuilder>();
            builder->buildLoggerName(default_logger_name);
            _default_logger = builder->build();
            _logger_map.insert(std::make_pair(default_logger_name, _default_logger));
        }
        ~LoggerManager() {}
        // 禁掉拷贝和赋值
        LoggerManager(const LoggerManager &) = delete;
        const LoggerManager &operator=(const LoggerManager &) = delete;

        std::mutex _mutex;
        Logger::ptr _default_logger;
        std::unordered_map<std::string, Logger::ptr> _logger_map;
    };

    class GlobalLoggerBuilder : public LoggerBuilder
    {
    public:
        virtual Logger::ptr build()
        {
            if (_logger_name.empty())
            {
                std::cout << "日志器名称为空！！\n";
                abort();
            }
            // 查找全局当中是否有该日志器
            Logger::ptr ret = LoggerManager::getInstance().getLogger(_logger_name);
            if (ret.get() != nullptr)
                return ret;
            if (_formatter.get() == nullptr)
            {
                _formatter = std::make_shared<Formatter>();
            }
            if (_fs_sinks.empty() && _db_sinks.empty())
            {
                _fs_sinks.push_back(LogSinkFactory::create_fs<StdoutSink>());
            }
            if (_logger_type == LoggerType::SYNC)
            {
                ret = std::make_shared<SyncLogger>(_logger_name, _limit_level, _formatter, _fs_sinks, _db_sinks);
            }
            else
            {
                // 后面实现完异步日志器之后完善
                ret = std::make_shared<AsyncLogger>(_logger_name, _limit_level, _formatter, _fs_sinks, _db_sinks, _async_type);
            }
            // 重置
            this->reset();
            LoggerManager::getInstance().addLogger(ret);
            return ret;
        }
    };

}


